#include <CGalaxy.h>
#include <CMPI.h>
#include <CGalaxy.h>
#include <CRasterizer.h>

string TAG = "GAMER::Gutil";


void printUsage() {
  cout << "Usage: \n" << endl;
  cout << "   gutil addnoise [source fits] [target fits] [noise rms]" << endl;
  cout << "   gutil normalize [source fits] [target fits] [max value]" << endl;
  cout << "   gutil create_rgb [source_r] [source_g] [source_b] [target bmp] [weight r] [weight g] [weight b] [power] [cutoff]" << endl;
  cout << "   gutil create_uniform_renderlist [# galaxies] [box size] [output]" << endl;
  cout << "   gutil clean [in fits] [out fits]" << endl;
  cout << "   gutil max [in fits] [out fits] max value" << endl;
  cout << "   gutil normalize [in fits] [out fits] [max value]" << endl;
  cout << "   gutil rotate [in fits] [out fits] [angle rad]" << endl;
  cout << "   gutil translate [in fits] [out fits] [dx] [dy]" << endl;
  cout << "   gutil pow [in fits] [out fits] [value]" << endl;
  cout << "   gutil resize [in fits] [out fits] [size]" << endl;
  cout << "   gutil convert [in bmp] [out fits]" << endl;
  cout << "   gutil convolve [in fits] [out fits] [std]" << endl;
  cout << endl;
}

void verifyArguments(int argc, int required) {
  if (argc != required)  {
    cout << "Syntax error: incorrect number of paramters " << endl;
    printUsage();
    exit(1);
  }
}

void createRGB(string s1, string s2, string s3, string out, CVector rgb, double power, double cutoff) {
  C2DImage imgR, imgG, imgB;
  imgR.LoadFits(s1);
  imgG.LoadFits(s2);
  imgB.LoadFits(s3);

  
  CBitMap bmpR, bmpG, bmpB;
  
  double m = imgR.getMax();
  m = max(m, imgG.getMax());
  m = max(m, imgB.getMax());
  imgR.Scale(1.0/m);
  imgG.Scale(1.0/m);
  imgB.Scale(1.0/m);

  imgR.Max(cutoff);
  imgG.Max(cutoff);
  imgB.Max(cutoff);

  m = imgR.getMax();
  m = max(m, imgG.getMax());
  m = max(m, imgB.getMax());
  imgR.Scale(1.0/m);
  imgG.Scale(1.0/m);
  imgB.Scale(1.0/m);



  imgR.Pow(power);
  imgG.Pow(power);
  imgB.Pow(power);
  
  imgR.Scale(255*rgb.x);
  imgG.Scale(255*rgb.y);
  imgB.Scale(255*rgb.z);
    
  imgR.ToBitMap(bmpR, CVector(1,0,0));
  imgG.ToBitMap(bmpG, CVector(0.0,1.0,0.0));
  imgB.ToBitMap(bmpB, CVector(0,0,1));
  
  bmpR.Add(bmpG);
  bmpR.Add(bmpB);
  
  bmpR.SaveBMP(out);

}

void CreateRandomRenderlist(double N, double W, string outfile) {

  ofstream f(outfile.c_str(), ios::out);
  srand(time(NULL));


  for (int i=0;i<N;i++) {
    
    int gal = rand()%7;
    //gal = 4;
    //gal = 3;
    string name = "";
    if (gal==0) 
      name = name + "SB0.gax";
    if (gal==1) 
      name = name + "E0.gax";
    if (gal==2) 
      name = name + "SAb.gax";
    if (gal==3) 
      name = name + "SB0.gax";
    if (gal==4) 
      name = name + "sombrero.gax";
    if (gal==5) 
      name = name + "SA2.gax";
    if (gal==6) 
      name = name + "irreg1.gax";
    
    // fwhm = 20;
    CVector orientation = CVector(1,1,1);
    orientation = orientation.RandomUniform().Normalize();
    //cout << orientation << endl;
    //orientation = CVector(1,-1,-0.5).Normalize();

    CVector position = CVector(W,W,W);
    position = position.RandomUniform();
    //position.Set(0,0,0);
    
    //    double mag = 0.1 + rand()%1500/1000.0;
    double mag = 1.0;

    f << name << " " << position.x << " " << position.y << " " << position.z;
    f <<" " << orientation.x <<  " " << orientation.y << " " << orientation.z << " " ;
    f << mag << endl;

  }
  f.close();
}

void clean(string in, string out) {
  C2DImage img;
  img.LoadFits(in);
  img.Clean();
  img.SaveFits(out, "Heisann");
}


void switchCommand(int argc, char* argv[]) {
  bool ok = false;
  string command = string(argv[1]);
  if (command=="addnoise") {
    verifyArguments(argc, 5);
    string src = string(argv[2]);
    string target = string(argv[3]);
    double val = strtod (argv[4],0);
    
    C2DImage img;
    img.LoadFits(src);
    img.AddNoise(val, false);
    img.SaveFits(target, TAG);
    ok = true;
  }

  if (command=="normalize") {
    verifyArguments(argc, 5);
    string src = string(argv[2]);
    string target = string(argv[3]);
    double val = strtod (argv[4],0);
    
    C2DImage img;
    img.LoadFits(src);
    img.Normalize(val);
    img.SaveFits(target, TAG);
    ok = true;
  }

  if (command=="create_rgb") {
    verifyArguments(argc, 11);
    CVector color(strtod (argv[6],0), strtod (argv[7],0),strtod (argv[8],0));
    createRGB(string(argv[2]),string(argv[3]), string(argv[4]), string(argv[5]), color, strtod (argv[9],0),strtod (argv[10],0)); 
    ok = true;
  }

  if (command=="create_uniform_renderlist") {
    //cout << "   gutil create_uniform_renderlist [# galaxies] [box size] [output]" << endl;
    verifyArguments(argc, 5);
    double count = strtod (argv[2],0);
    double boxsize = strtod (argv[3],0);
    string outfile = string(argv[4]);
    CreateRandomRenderlist(count, boxsize, outfile);
    ok = true;
  }

  if (command=="clean") {
    verifyArguments(argc, 4);
    clean(string(argv[2]), string(argv[3]));
    ok = true;
  }

  if (command=="max") {
    verifyArguments(argc, 5);
    C2DImage img;
    img.LoadFits(string(argv[2]));
    img.Max(strtod (argv[4],0));
    img.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="normalize") {
    verifyArguments(argc, 5);
    C2DImage img;
    img.LoadFits(string(argv[2]));
    img.Normalize(strtod (argv[4],0));
    img.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="rotate") {
    verifyArguments(argc, 5);
    C2DImage img, target;
    img.LoadFits(string(argv[2]));
    img.Rotate(target, strtod (argv[4],0));
    target.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="translate") {
    verifyArguments(argc, 6);
    C2DImage img, target;
    img.LoadFits(string(argv[2]));
    img.Translate(target, strtod (argv[5],0), strtod (argv[4],0));
    target.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="pow") {
    verifyArguments(argc, 5);
    C2DImage img;
    img.LoadFits(string(argv[2]));
    img.Pow(strtod (argv[4],0));
    img.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="resize") {
    verifyArguments(argc, 5);
    C2DImage img;
    img.LoadFits(string(argv[2]));
    //img.Resize(strtod (argv[4],0));
    img.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="convert") {
    verifyArguments(argc, 4);
    C2DImage img;
    img.LoadBMP(string(argv[2]));
    //img.Resize(strtod (argv[4],0));
    img.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }
  if (command=="convolve") {
    verifyArguments(argc, 5);
    C2DImage img;
    img.LoadFits(string(argv[2]));
    double c = strtod (argv[4],0);
    if (c!=0.0)
      img.Convolve(strtod (argv[4],0));
    //img.Resize(strtod (argv[4],0));
    img.SaveFits(string(argv[3]), "Heisann");
    ok = true;
  }


  

    if (!ok)
      printUsage();

}


int main(int argc, char *argv[]) {
 
   // Wrapper: loads ini file and initialized all
  srand(time(NULL));
  
  if ( argc == 1 ) {
    printUsage();
   exit(1);
  }
  
  try {
    switchCommand(argc, argv);


  } catch (string s) {
    cout << s<< endl;
    exit(1);
  }
  catch (...) {
    cout << "Undefined error. Check your syntax and parameters!" << endl;
    exit(1);
  }
  
  
  return 0;
}
